﻿//------------------------------------------------------------------------------
// <copyright file="Settings.cs" company="Robert MacLean">
//      Copyright © Robert MacLean.  All Rights Reserved.
// </copyright>
//
//  Details on this see: http://pepper.codeplex.com
//  This code released under the terms of the 
//  Microsoft Public License  (MS-PL, http://opensource.org/licenses/ms-pl.html.)
//------------------------------------------------------------------------------

namespace Pepper.Core
{
    using System.Xml;
    using EnvDTE80;
    using System.Runtime.InteropServices;
    using System;
    using System.Globalization;
    using System.IO;
    using System.Security.Cryptography;
    using System.ServiceModel;
    using Pepper.Services.Settings;

    public class Settings
    {
        private static PepperService2Client GetService()
        {
            var binding = new BasicHttpBinding()
            {
                AllowCookies = false,
                BypassProxyOnLocal = true,
                ReaderQuotas = new XmlDictionaryReaderQuotas()
                {
                    MaxArrayLength = int.MaxValue,
                    MaxBytesPerRead = int.MaxValue,
                    MaxDepth = int.MaxValue,
                    MaxNameTableCharCount = int.MaxValue,
                    MaxStringContentLength = int.MaxValue
                },
                MaxBufferSize = int.MaxValue,
                MaxReceivedMessageSize = int.MaxValue,
                UseDefaultWebProxy = true,
                SendTimeout = new TimeSpan(0, 10, 0),
                ReceiveTimeout = new TimeSpan(0, 10, 0)
            };

            //var endPoint = new EndpointAddress("http://4eb52660acbb43a18151f36ecaa451e8.cloudapp.net/PepperService.svc?wsdl");
            var endPoint = new EndpointAddress("http://localhost:48928/PepperService2.svc?wsdl");
            return new PepperService2Client(binding, endPoint);
        }

        public static Guid Login(string username, string password)
        {
            var service = GetService();
            try
            {
                return service.Login(username, password.Hash());
            }
            catch (FaultException<InvalidCredentialsFault> err)
            {
                var fault = err.Detail;
                throw new PepperCoreException(string.Format(CultureInfo.CurrentCulture, "{0}: {1}", fault.FaultIdk__BackingField, fault.Messagek__BackingField));
            }
            finally
            {
                service.Close();
            }
        }

        public static int SettingsCount()
        {
            var service = GetService();
            try
            {
                return service.SettingsCount();
            }
            finally
            {
                service.Close();
            }
        }

        public static void Clear(string username, string password)
        {
            var service = GetService();
            try
            {
                var userid = service.Login(username, password);
                service.ClearSetting(userid, password.Hash());
            }
            catch (FaultException<InvalidCredentialsFault> err)
            {
                var fault = err.Detail;
                throw new PepperCoreException(string.Format(CultureInfo.CurrentCulture, "{0}: {1}", fault.FaultIdk__BackingField, fault.Messagek__BackingField));
            }
            catch (FaultException<NoSettingsFault>)
            {
                throw new PepperCoreException("Could not find any settings for you.");
            }
            finally
            {
                service.Close();
            }
        }

        public static bool AreSettingsPublic(Guid publicSettingsId)
        {
            var service = GetService();
            try
            {
                return service.AreSettingsPublic(publicSettingsId);
            }
            catch (FaultException<InvalidCredentialsFault> err)
            {
                var fault = err.Detail;
                throw new PepperCoreException(string.Format(CultureInfo.CurrentCulture, "{0}: {1}", fault.FaultIdk__BackingField, fault.Messagek__BackingField));
            }
            catch (FaultException<NoSettingsFault>)
            {
                throw new PepperCoreException("Could not find any settings for you.");
            }
            finally
            {
                service.Close();
            }
        }

        public static string GetVisualStudioSettings()
        {
            var dumpPath = Path.GetTempFileName();
            try
            {
                var dte = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.10.0");
                dte.ExecuteCommand("Tools.ImportandExportSettings", string.Format(CultureInfo.CurrentCulture, "/export:\"{0}\"", dumpPath));

                return File.ReadAllText(dumpPath);
            }
            finally
            {
                File.Delete(dumpPath);
            }
        }

        public static void UploadSettings(Guid userId, string password, string settings, bool publicSettings = false)
        {
            var service = GetService();
            try
            {
                service.SaveSettings(userId, password.Hash(), settings.EncryptToBytes(password), settings.Hash(), publicSettings);
            }
            catch (FaultException<InvalidCredentialsFault> err)
            {
                var fault = err.Detail;
                throw new PepperCoreException(string.Format(CultureInfo.CurrentCulture, "{0}: {1}", fault.FaultIdk__BackingField, fault.Messagek__BackingField));
            }
            finally
            {
                service.Close();
            }
        }

        public static void SaveSettings(Guid userId, string password)
        {
            UploadSettings(userId, password, GetVisualStudioSettings());
        }

        public static string DownloadSettings(Guid userId, string password)
        {
            Tuple<byte[], string> settingsResult = null;
            var service = GetService();
            try
            {
                settingsResult = service.LoadSettings(userId, password.Hash());
            }
            catch (FaultException<InvalidCredentialsFault> err)
            {
                var fault = err.Detail;
                throw new PepperCoreException(string.Format(CultureInfo.CurrentCulture, "{0}: {1}", fault.FaultIdk__BackingField, fault.Messagek__BackingField));
            }
            catch (FaultException<NoSettingsFault>)
            {
                throw new PepperCoreException("Could not find any settings for you.");
            }
            finally
            {
                service.Close();
            }

            var hash = settingsResult.Item2;
            string settings = null;
            try
            {
                settings = settingsResult.Item1.DecryptFromBytes(password);
            }
            catch (CryptographicException err)
            {
                throw new PepperCoreException("0x20000001: Invalid password - make sure the password you used is the same as previously.", err);
            }

            if (String.Compare(hash, settings.Hash(), false) == 0)
            {
                return settings;
            }
            else
            {
                throw new PepperCoreException("0x20000002: Invalid password - make sure the password you used is the same as previously.");
            }
        }

        public static void ImportVisualStudioSettings(string filePath)
        {
            var dte = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.10.0");
            dte.ExecuteCommand("Tools.ImportandExportSettings", string.Format(CultureInfo.CurrentCulture, "/import:\"{0}\"", filePath));
        }
    }
}
